#include "systemclass.h"


SystemClass::SystemClass()
{
	m_Input = 0;
	m_Graphics = 0;
	m_Level2 = 0;
	m_Menu = 0;
	m_Fps = 0;
	m_MyMouse = 0;
	m_HighScoreList = 0;
	m_TimeCountDown = 0;
}


SystemClass::SystemClass(const SystemClass& other)
{
}


SystemClass::~SystemClass()
{
}


bool SystemClass::Initialize()
{
	//int screenWidth, screenHeight;
	bool result;

	gamestat = GAMESTAT::MENU;
	MenuIsStarted = false;
	Level1IsStarted = false;
	Level2IsStarted = false;
	EscapeIsPressed = false;

	// Initialize the width and height of the screen to zero before sending the variables into the function.
	screenWidth = 0;
	screenHeight = 0;

	// Initialize the windows api.
	InitializeWindows(screenWidth, screenHeight);

	m_MyMouse = new MyMouse;
	m_MyMouse->LeftButtonPressed = false;
	m_MyMouse->RightButtonPressed = false;

	m_HighScoreList = new HighScoreList();
	m_HighScoreList->ReadFromFile("highscore.txt");

	// Create the input object.  This object will be used to handle reading the keyboard input from the user.
	m_Input = new InputClass;
	if(!m_Input)
	{
		return false;
	}

	// Initialize the input object.
	result = m_Input->Initialize(m_hinstance, m_hwnd, screenWidth, screenHeight);
	if(!result)
	{
		MessageBox(m_hwnd, L"Could not initialize the input object.", L"Error", MB_OK);
		return false;
	}

	// Create menu objects. This object will handle the menu
	m_Menu = new MenuClass();
	if(!m_Menu)
	{
		return false;
	}

	// Initialize menu object
	result = m_Menu->Initialize(screenWidth, screenHeight, m_hwnd);
	if(!result)
	{
		return false;
	}

	// Move to member function
	// Create the graphics object.  This object will handle level 1.
	m_Graphics = new GraphicsClass();
	if(!m_Graphics)
	{
		return false;
	}

	m_Level2 = new Level2();
	if (!m_Level2)
	{
		return false;
	}

	/*
	// Initialize the graphics object.
	result = m_Graphics->Initialize(screenWidth, screenHeight, m_hwnd);
	if(!result)
	{
		return false;
	}*/

	// Create the fps object.
	m_Fps = new FpsClass;
	if(!m_Fps)
	{
		return false;
	}

	// Initialize the fps object.
	m_Fps->Initialize();

	m_TimeCountDown = new EllapsedTimer();
	if(!m_TimeCountDown)
	{
		return false;
	}
	
	return true;
}


void SystemClass::Shutdown()
{
	// Release the fps object.
	if(m_Fps)
	{
		delete m_Fps;
		m_Fps = 0;
	}

	if(m_TimeCountDown)
	{
		delete m_TimeCountDown;
		m_TimeCountDown = 0;
	}

	if(m_HighScoreList)
	{
		delete m_HighScoreList;
		m_HighScoreList = 0;
	}

	// Release menu object
	if (m_Menu)
	{
		m_Menu->Shutdown();
		delete m_Menu;
		m_Menu = 0;
	}

	// Release the graphics object.
	if(m_Graphics)
	{
		m_Graphics->Shutdown();
		delete m_Graphics;
		m_Graphics = 0;
	}

	if (m_Level2)
	{
		m_Level2->Shutdown();
		delete m_Level2;
		m_Level2 = 0;
	}

	// Release the input object.
	if(m_Input)
	{
		m_Input->Shutdown();
		delete m_Input;
		m_Input = 0;
	}

	if (m_MyMouse)
	{
		delete m_MyMouse;
	}

	// Shutdown the window.
	ShutdownWindows();
	
	return;
}


void SystemClass::Run()
{
	MSG msg;
	bool result;


	// Initialize the message structure.
	ZeroMemory(&msg, sizeof(MSG));
	
	// Loop until there is a quit message from the window or the user.
	done = false;
	while(!done)
	{
		// Handle the windows messages.
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		// If windows signals to end the application then exit out.
		if(msg.message == WM_QUIT)
		{
			done = true;
		}
		else
		{
			// Otherwise do the frame processing.
			result = Frame();
			if(!result)
			{
				MessageBox(m_hwnd, L"Frame Processing Failed", L"Error", MB_OK);
				done = true;
			}
		}

		// Check if the user pressed escape and wants to quit.
		if(!EscapeIsPressed || m_TimeCountDown->timedOut())
		{
			
			if(m_Input->IsEscapePressed() == true || m_TimeCountDown->timedOut())
			{
				m_TimeCountDown->StoppTimer();
				//done = true;
				EscapeIsPressed = true;
				int points;
				if (Level1IsStarted)
					points = m_Graphics->GetPoints();
				else if (Level2IsStarted)
					points = m_Level2->GetPoints();
				if(m_HighScoreList->InToList(points))
				{
					DialogBox(m_hinstance,
						MAKEINTRESOURCE(IDD_DIALOG1),
						m_hwnd,
						reinterpret_cast<DLGPROC>(DlgProc));
					//reinterpret_cast<DLGPROC>(DlgProc));
					HighScore hs;
					hs.SetName(m_Name);
					hs.SetPoints(points);
					m_HighScoreList->AddScore(hs);
				}
				MenuIsStarted = false;
				gamestat = GAMESTAT::MENU;
			}
		}
		//Check if points is 5, then level2
		if (Level1IsStarted && m_Graphics->GetPoints() >= 5)
		{
			Level1IsStarted = false;
			points = m_Graphics->GetPoints();
			gamestat = GAMESTAT::LEVEL2;
		}
	}

	m_HighScoreList->WriteToFIle("highscore.txt");

	return;
}


bool SystemClass::Frame()
{
	bool result;
	int mouseX, mouseY;
	int keyX, keyY;
	int textX1, textY1, textX2, textY2;

	// Update the system stats.
	m_Fps->Frame();
	
	// Do the input frame processing.
	result = m_Input->Frame();
	if(!result)
	{
		return false;
	}

	// Get the location of the mouse from the input object,
	//m_Input->GetMouseLocation(mouseX, mouseY);

	switch(gamestat)
	{
	case GAMESTAT::MENU:
		// Close down all Level objects
		
		if (!MenuIsStarted)
		{
			if(m_Graphics)
			{
				points = m_Graphics->GetPoints();
				m_Graphics->Shutdown();
			}
			if (m_Level2)
			{
				m_Level2->Shutdown();
			}
			MenuIsStarted = true;
		}
		
		if (m_MyMouse->LeftButtonPressed)
		{
			m_MyMouse->LeftButtonPressed = false;
			mouseX = m_MyMouse->Xpos;
			mouseY = m_MyMouse->Ypos;
			m_Menu->m_Start->GetPosition(textX1, textY1);
			m_Menu->m_Start->GetSize(textX2, textY2);
			//Start new game
			if (mouseX > textX1 && mouseX < textX2 && mouseY > textY1 && mouseY < textY2)
			{
				Level1IsStarted = false;
				
				gamestat = GAMESTAT::LEVEL1;
			}
			//Show high score
			m_Menu->m_HighScoreList->GetPosition(textX1, textY1);
			m_Menu->m_HighScoreList->GetSize(textX2, textY2);
			if (mouseX > textX1 && mouseX < textX2 && mouseY > textY1 && mouseY < textY2)
			{
				m_HighScoreList->ShowList();
			}
			//Avsluta programmet
			m_Menu->m_Quit->GetPosition(textX1, textY1);
			m_Menu->m_Quit->GetSize(textX2, textY2);
			if (mouseX > textX1 && mouseX < textX2 && mouseY > textY1 && mouseY < textY2)
			{
				done = true;
			}
		}

		// Do frame processing for Menu object
		result = m_Menu->Frame(0, 0);
		if(!result)
		{
			return false;
		}

		// Render Menu object
		result = m_Menu->Render();
		if (!result)
		{
			return false;
		}
		break;
	case GAMESTAT::LEVEL1:
		EscapeIsPressed = false;
		// Initialize Level 1 object
		if(!Level1IsStarted)
		{
			StartLevel1(screenWidth, screenHeight, m_hwnd);
			m_Graphics->SetPoints(0);
			m_TimeCountDown->startTimer(30000);
			Level1IsStarted = true;
		}
		m_TimeCountDown->updateTimer();
		m_Input->GetKeyboardCoord(keyX, keyY);

		// Do the frame processing for the graphics object.
		result = m_Graphics->Frame(keyX, keyY, m_Fps->GetFps(), m_TimeCountDown->GetTimeLeft());
		if(!result)
		{
			return false;
		}

		// Finally render the graphics to the screen.
		result = m_Graphics->Render();
		if(!result)
		{
			return false;
		}
		break;
	case GAMESTAT::LEVEL2:
		EscapeIsPressed = false;
		// Initialize Level 1 object
		if (!Level2IsStarted)
		{
			StartLevel2(screenWidth, screenHeight, m_hwnd);
			m_Level2->SetPoints(points);
			m_TimeCountDown->startTimer(30000);
			Level2IsStarted = true;
		}
		if (m_Level2->GetTimeIncrease())
			m_TimeCountDown->increaseTime(10000);
		m_TimeCountDown->updateTimer();
		m_Input->GetKeyboardCoord(keyX, keyY);

		// Do the frame processing for the graphics object.
		result = m_Level2->Frame(keyX, keyY, m_Fps->GetFps(), m_TimeCountDown->GetTimeLeft());
		if (!result)
		{
			return false;
		}

		// Finally render the graphics to the screen.
		result = m_Level2->Render();
		if (!result)
		{
			return false;
		}
		break;
	}

	return true;
}


LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
	switch(umsg)
	{
	case WM_LBUTTONUP:
		{
			m_MyMouse->Xpos = LOWORD(lparam);
			m_MyMouse->Ypos = HIWORD(lparam);
			m_MyMouse->LeftButtonPressed = true;
			break;
		}
	
	}
	return DefWindowProc(hwnd, umsg, wparam, lparam);
}

LRESULT CALLBACK SystemClass::DialogMessageHandler(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	//wchar_t *namn;
	switch(Msg)
	{
	case WM_COMMAND:
		switch(wParam)
		{
		case IDOK:
			GetDlgItemText(hWndDlg,IDC_EDIT1,m_Name,49);
			//SetName(namn);
			EndDialog(hWndDlg, 0);
			return TRUE;
		case IDCANCEL:
			EndDialog(hWndDlg, 0);
			return TRUE;
		}
		break;
	}

	return FALSE;
}


void SystemClass::InitializeWindows(int& screenWidth, int& screenHeight)
{
	WNDCLASSEX wc;
	DEVMODE dmScreenSettings;
	int posX, posY;


	// Get an external pointer to this object.	
	ApplicationHandle = this;

	// Get the instance of this application.
	m_hinstance = GetModuleHandle(NULL);

	// Give the application a name.
	m_applicationName = L"FairyFly";

	// Setup the windows class with default settings.
	wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = m_hinstance;
	wc.hIcon		 = LoadIcon(NULL, IDI_WINLOGO);
	wc.hIconSm       = wc.hIcon;
	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = m_applicationName;
	wc.cbSize        = sizeof(WNDCLASSEX);
	
	// Register the window class.
	RegisterClassEx(&wc);

	// Determine the resolution of the clients desktop screen.
	screenWidth  = GetSystemMetrics(SM_CXSCREEN);
	screenHeight = GetSystemMetrics(SM_CYSCREEN);

	// Setup the screen settings depending on whether it is running in full screen or in windowed mode.
	if(::FULL_SCREEN)
	{
		// If full screen set the screen to maximum size of the users desktop and 32bit.
		memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
		dmScreenSettings.dmSize       = sizeof(dmScreenSettings);
		dmScreenSettings.dmPelsWidth  = (unsigned long)screenWidth;
		dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight;
		dmScreenSettings.dmBitsPerPel = 32;			
		dmScreenSettings.dmFields     = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

		// Change the display settings to full screen.
		ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);

		// Set the position of the window to the top left corner.
		posX = posY = 0;
	}
	else
	{
		// If windowed then set it to 800x600 resolution.
		screenWidth  = 800;
		screenHeight = 600;

		// Place the window in the middle of the screen.
		posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth)  / 2;
		posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / 2;
	}

	// Create the window with the screen settings and get the handle to it.
	m_hwnd = CreateWindowEx(WS_EX_APPWINDOW, m_applicationName, m_applicationName, 
						    WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
							//WS_OVERLAPPEDWINDOW,
						    posX, posY, screenWidth, screenHeight, NULL, NULL, m_hinstance, NULL);

	// Bring the window up on the screen and set it as main focus.
	ShowWindow(m_hwnd, SW_SHOW);
	SetForegroundWindow(m_hwnd);
	SetFocus(m_hwnd);

	// Hide the mouse cursor.
	ShowCursor(true);

	return;
}


void SystemClass::ShutdownWindows()
{
	// Show the mouse cursor.
	ShowCursor(true);

	// Fix the display settings if leaving full screen mode.
	if(::FULL_SCREEN)
	{
		ChangeDisplaySettings(NULL, 0);
	}

	// Remove the window.
	DestroyWindow(m_hwnd);
	m_hwnd = NULL;

	// Remove the application instance.
	UnregisterClass(m_applicationName, m_hinstance);
	m_hinstance = NULL;

	// Release the pointer to this class.
	ApplicationHandle = NULL;

	return;
}


LRESULT CALLBACK WndProc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
{
	switch(umessage)
	{
	
		// Check if the window is being destroyed.
		case WM_DESTROY:
		{
			PostQuitMessage(0);
			return 0;
		}

		// Check if the window is being closed.
		case WM_CLOSE:
		{
			PostQuitMessage(0);		
			return 0;
		}

		// All other messages pass to the message handler in the system class.
		default:
		{
			return ApplicationHandle->MessageHandler(hwnd, umessage, wparam, lparam);
		}
	}
}

bool SystemClass::StartLevel1(int screenWidth, int screenHeight, HWND hwnd)
{
	bool result;

	// Initialize the graphics object.
	result = m_Graphics->Initialize(screenWidth, screenHeight, m_hwnd);
	if(!result)
	{
		return false;
	}
	return true;
}

bool SystemClass::StartLevel2(int screenWidth, int screenHeight, HWND hwnd)
{
	bool result;
	//Initialize the graphics object
	result = m_Level2->Initialize(screenWidth, screenHeight, m_hwnd);
	if (!result)
	{
		return false;
	}
	return true;
}

LRESULT CALLBACK DlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	//wchar_t *namn;
	switch(Msg)
	{
	case WM_INITDIALOG:
		return TRUE;

	// All other messages pass to the message handler in the system class.
	default:
		{
			return ApplicationHandle->DialogMessageHandler(hWndDlg, Msg, wParam, lParam);
		}
	}
	
}